﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Reflection;
using System.IO;
using Summer.Exception;
using Summer.IO;
using System.Collections;
using Summer.Core.Config;
using Summer.Object;
using Summer.Log;
#region License
/*
 *  Copyright (c) Dumuzi.cn 2009 , All rights reserved.
 *  CLR Version:  2.0.50727.4927
 *  NameSpace: Summer.Core.Aop
 *  Author:Edwin Tai,戴佳顺
 *  Msn:edwin19861218@hotmail.com
 *  QQ: 1961218
 *  Date:2009/10/27 16:37:20
 *  Licensed under the Microsoft Public License (Ms-PL)
 *  This license governs use of the accompanying software. 
 *  If you use the software, you accept this license.
 *  If you do not accept the license, do not use the software.
 */
#endregion

namespace Summer.Core.Aop
{
    /// <summary>
    /// Configuration about the config file of Aop
    /// In order to get function names and new instance of IAdvice
    /// </summary>
    public class AopConfiguration : IConfiguration<SummerConfig>
    {
        private static ILog logger = LogFactory.GetLogger(typeof(AopConfiguration), false);
        /// <summary>
        /// Get function name by aspect value and advice type
        /// </summary>
        /// <param name="aspectXml"></param>
        /// <param name="aspectName"></param>
        /// <param name="advice"></param>
        /// <returns></returns>
        public  string[] GetFunctionNames(string aspectXml, string aspectName, AdviceEnum advice)
        {
            ArrayList names = new ArrayList();
            SummerConfig config = GetConfigFile(aspectXml);
            var aspects = config.AopConfig.Aspects.Where(x => x.Value == aspectName)
                .Select(y => y.Advices.Where(z => z.Type == advice.ToString())
                    .Select(z => z.Pointcuts));
            foreach (var a in aspects)
            {
                foreach (var b in a)
                {
                    foreach (var c in b)
                    {
                        names.Add(c.Value);
                    }
                }
            }
            return (string[])names.ToArray(typeof(string));
        }
        /// <summary>
        /// Get instance of IAdvice by aspect value and advice type
        /// </summary>
        /// <param name="aspectXml"></param>
        /// <param name="aspectName"></param>
        /// <param name="advice"></param>
        /// <returns></returns>
        public IAdvice GetAdvice(string aspectXml, string aspectName, AdviceEnum advice)
        {
            string classPath = string.Empty;
            SummerConfig config = GetConfigFile(aspectXml);
            var aspects = config.AopConfig.Aspects.Where(x => x.Value == aspectName)
                .Select(y => y.Advices.Where(z => z.Type == advice.ToString())
                    .Select(z => z.Class));
            foreach (var a in aspects)
            {
                foreach (var b in a)
                {
                    if (b.Trim() != string.Empty)
                    {
                        classPath = b;
                        break;
                    }
                }
            }
            try
            {
                return (IAdvice)classPath.LoadLibrary();
            }
            catch
            {
                throw new AopException("Load Library Failure", this.GetType());
            }
        }
        #region IConfiguration<AspectConfig> 成员
        //TODO Get it by preload
        /// <summary>
        /// Get the config 
        /// </summary>
        /// <param name="aspectXml">xml file path</param>
        /// <returns>Advice tree contained with pointcut</returns>
        public SummerConfig GetConfigFile(string aspectXml)
        {
            return GetConfigFiles(new string[] { aspectXml });
        }

        public SummerConfig GetConfigFiles(string[] configXmls)
        {
            //load config
            SummerConfig config = new SummerConfig() 
            {
                AopConfig = new SummerConfig.Aop() 
                {
                    Aspects = new SummerConfig.Aop.Aspect[] { }
                } 
            };
            foreach (string configXml in configXmls)
            {
                SummerConfig s = LoadConfigFile(configXml);
                //load aop-aspect
                config.AopConfig.Aspects = (SummerConfig.Aop.Aspect[])config.AopConfig.Aspects.MergeArray(s.AopConfig.Aspects);
            }
            //merge config
            SummerConfig.Aop.Aspect[] aspects = config.AopConfig.Aspects;
            List<SummerConfig.Aop.Aspect> aspectList = new List<SummerConfig.Aop.Aspect>();
            foreach (var v in aspects)
            {
                var temp = aspectList.Find((SummerConfig.Aop.Aspect o) => { return (o.Value == v.Value); });
                if (temp == null)
                {
                    //Unexist in the list
                    aspectList.Add(v);
                }
                else
                {
                    ArrayList adviceList=new ArrayList();
                    //copy temp.advices to adviceList
                    temp.Advices.CopyTo(adviceList, (object o) => { return true; });
                    Func<SummerConfig.Aop.Advice,bool> fuc = delegate(SummerConfig.Aop.Advice ad)
                    {
                        foreach (var obj in adviceList)
                        {
                            if (((SummerConfig.Aop.Advice)obj).Type == ad.Type)
                            {
                                logger.Warn("Advice type named {0} is missed for the Advice with the same type exists", ad.Type);
                                return false;
                            }
                        }
                        return true;
                    };
                    //copy v.advice to adviceList and judge if exist
                    v.Advices.CopyTo(adviceList, (object o) => 
                    {
                        SummerConfig.Aop.Advice ad = (SummerConfig.Aop.Advice)o;
                        return fuc(ad);
                    });
                    temp.Advices = (SummerConfig.Aop.Advice[])adviceList.ToArray(typeof(SummerConfig.Aop.Advice));
                }

            }
            config.AopConfig.Aspects = aspectList.ToArray();
            return config;
        }

        public SummerConfig LoadConfigFile(string configXml)
        {
            configXml = configXml.FindPath(new IocException("Config File Not Exist", this.GetType()));
            return new AspectConfigParser().Load(configXml);
        }

        #endregion
    }
}
